home *** CD-ROM | disk | FTP | other *** search
/ Amiga Tools 2 / Amiga Tools 2.iso / tools / jade / src / edit.c < prev    next >
C/C++ Source or Header  |  1995-03-09  |  19KB  |  783 lines

  1. /* edit.c -- Editing buffers
  2.    Copyright (C) 1993, 1994 John Harper <jsh@ukc.ac.uk>
  3.  
  4.    This file is part of Jade.
  5.  
  6.    Jade is free software; you can redistribute it and/or modify it
  7.    under the terms of the GNU General Public License as published by
  8.    the Free Software Foundation; either version 2, or (at your option)
  9.    any later version.
  10.  
  11.    Jade is distributed in the hope that it will be useful, but
  12.    WITHOUT ANY WARRANTY; without even the implied warranty of
  13.    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.     See the
  14.    GNU General Public License for more details.
  15.  
  16.    You should have received a copy of the GNU General Public License
  17.    along with Jade; see the file COPYING.    If not, write to
  18.    the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  19.  
  20. #include "jade.h"
  21. #include "jade_protos.h"
  22.  
  23. #include <string.h>
  24. #include <stdlib.h>
  25. #include <ctype.h>
  26.  
  27. #ifdef NEED_MEMORY_H
  28. # include <memory.h>
  29. #endif
  30.  
  31. _PR bool clear_line_list(TX *);
  32. _PR void kill_line_list(TX *);
  33. _PR LINE *resize_line_list(TX *, long, long);
  34. _PR bool insert_gap(TX *, long, const POS *);
  35. _PR bool insert_str(TX *, const u_char *, POS *);
  36. _PR bool insert_str_n(TX *, const u_char *, long, POS *);
  37. _PR bool insert_string(TX *, const u_char *, long, POS *);
  38. _PR bool delete_chars(TX *, const POS *, long);
  39. _PR bool delete_lines(TX *, long, long);
  40. _PR bool delete_section(TX *, POS *, POS *);
  41. _PR bool split_line(TX *, POS *);
  42. static bool join_lines(TX *, POS *);
  43. _PR bool pad_pos(TX *, POS *);
  44. _PR bool pad_cursor(VW *);
  45. _PR void order_pos(POS *, POS *);
  46. _PR bool check_section(TX *, POS *, POS *);
  47. _PR void check_pos(TX *, POS *);
  48. _PR bool check_line(TX *, POS *);
  49. _PR long section_length(TX *, POS *, POS *);
  50. _PR void copy_section(TX *, POS *, POS *, u_char *);
  51. _PR bool pos_in_block(VW *, long, long);
  52. _PR bool cursor_in_block(VW *);
  53. _PR bool page_in_block(VW *);
  54. _PR short line_in_block(VW *, long);
  55. _PR void order_block(VW *);
  56. _PR void set_block_refresh(VW *);
  57. _PR bool read_only(TX *);
  58.  
  59. #define ALLOC_LL(n)   mymalloc(sizeof(LINE) * (n))
  60. #define FREE_LL(l)    myfree(l)
  61.  
  62. /*
  63.  * This copies a line list (or part of one).
  64.  * d = destination
  65.  * s = source
  66.  * n = number of LINE's to copy.
  67.  */
  68. #define MOV_LL(d,s,n) memcpy((d), (s), (n) * sizeof(LINE))
  69. /*
  70.  * void
  71.  * MOV_LL(LINE *dst, LINE *src, long number)
  72.  * {
  73.  *     memcpy(dst, src, number * sizeof(LINE));
  74.  * }
  75.  */
  76.  
  77. /*
  78.  * Makes file empty (null string in first line)
  79.  */
  80. bool
  81. clear_line_list(TX *tx)
  82. {
  83.     if(tx->tx_Lines)
  84.     kill_line_list(tx);
  85.     tx->tx_Lines = ALLOC_LL(1);
  86.     if(tx->tx_Lines)
  87.     {
  88.     tx->tx_Lines[0].ln_Line = str_dupn("", 0);
  89.     if(tx->tx_Lines[0].ln_Line)
  90.         tx->tx_Lines[0].ln_Strlen = 1;
  91.     else
  92.         tx->tx_Lines[0].ln_Strlen = 0;
  93.     tx->tx_NumLines = 1;
  94.     return(TRUE);
  95.     }
  96.     return(FALSE);
  97. }
  98.  
  99. /*
  100.  * deallocates all lines and their list
  101.  */
  102. void
  103. kill_line_list(TX *tx)
  104. {
  105.     if(tx->tx_Lines)
  106.     {
  107.     LINE *line;
  108.     long i;
  109.     for(i = 0, line = tx->tx_Lines; i < tx->tx_NumLines; i++, line++)
  110.     {
  111.         if(line->ln_Strlen)
  112.         str_free(line->ln_Line);
  113.     }
  114.     FREE_LL(tx->tx_Lines);
  115.     tx->tx_Lines = NULL;
  116.     tx->tx_NumLines = 0;
  117.     }
  118. }
  119.  
  120. /*
  121.  * deallocates some lines (but not the list)
  122.  */
  123. static void
  124. kill_some_lines(TX *tx, long start, long number)
  125. {
  126.     LINE *line = tx->tx_Lines + start;
  127.     long i;
  128.     for(i = 0; i < number; i++, line++)
  129.     {
  130.     if(line->ln_Strlen)
  131.     {
  132.         str_free(line->ln_Line);
  133.         line->ln_Strlen = 0;
  134.         line->ln_Line = NULL;
  135.     }
  136.     }
  137. }
  138.  
  139. /*
  140.  * Creates blank entries or removes existing lines starting from line 'where'
  141.  * 'change' is the number of lines to insert, negative numbers mean delete
  142.  * that number of lines starting at the cursor line.
  143.  * If lines are deleted the actual text is also deleted.
  144.  * NOTE: You can't have a line list of zero lines.
  145.  */
  146. LINE *
  147. resize_line_list(TX *tx, long change, long where)
  148. {
  149.     LINE *newlines;
  150.     long newsize = tx->tx_NumLines + change;
  151.     if((newsize > 0) && (newlines = ALLOC_LL(newsize)))
  152.     {
  153.     if(tx->tx_Lines)
  154.     {
  155.         if(change > 0)
  156.         {
  157.         MOV_LL(newlines, tx->tx_Lines, where);
  158.         MOV_LL(newlines + where + change, tx->tx_Lines + where, tx->tx_NumLines - where);
  159.         }
  160.         else
  161.         {
  162.         MOV_LL(newlines, tx->tx_Lines, where);
  163.         MOV_LL(newlines + where, tx->tx_Lines + where - change, tx->tx_NumLines - where + change);
  164.         kill_some_lines(tx, where, -change);
  165.         }
  166.         FREE_LL(tx->tx_Lines);
  167.     }
  168.     if(change > 0)
  169.         bzero(newlines + where, change * sizeof(LINE));
  170.     tx->tx_Lines = newlines;
  171.     tx->tx_NumLines = newsize;
  172.     return(newlines);
  173.     }
  174.     return(FALSE);
  175. }
  176.  
  177. #if 0
  178. /*
  179.  * Pastes a line into the current view at line num.
  180.  * a LINE should have been made if it is wanted.
  181.  * text is not copied, it should have been mymalloc()'ed (or savestring()'ed)
  182.  */
  183. bool
  184. stuffline(TX *tx, u_char *text, long lineNum)
  185. {
  186.     LINE *line = tx->tx_Lines + lineNum;
  187.     if(line->ln_Strlen)
  188.     str_free(line->ln_Line);
  189.     line->ln_Strlen = strlen(text) + 1;
  190.     line->ln_Line = text;
  191.     return(TRUE);
  192. }
  193. #endif
  194.  
  195. /*
  196.  * Inserts some `space' at pos. The gap will be filled with random garbage.
  197.  * pos is *not* altered.
  198.  */
  199. bool
  200. insert_gap(TX *tx, long len, const POS *pos)
  201. {
  202.     LINE *line = tx->tx_Lines + pos->pos_Line;
  203.     u_char *newline = str_alloc(len + line->ln_Strlen);
  204.     if(newline)
  205.     {
  206.     if(line->ln_Strlen)
  207.     {
  208.         memcpy(newline, line->ln_Line, pos->pos_Col);
  209.         memcpy(newline + pos->pos_Col + len, line->ln_Line + pos->pos_Col,
  210.            line->ln_Strlen - pos->pos_Col);
  211.         str_free(line->ln_Line);
  212.     }
  213.     else
  214.         newline[len] = 0;
  215.     line->ln_Line = newline;
  216.     line->ln_Strlen += len;
  217.     adjust_marks_add_x(tx, len, pos->pos_Col, pos->pos_Line);
  218.     return(TRUE);
  219.     }
  220.     mem_error();
  221.     return(FALSE);
  222. }
  223.  
  224. /*
  225.  * Inserts a string into the current line at the cursor pos
  226.  *
  227.  * IMPORTANT: For any of the next functions which insert text the pos
  228.  * argument must not be one which will be fiddled with by the keeppos*()
  229.  * functions (specifically a direct pointer to vw_CursorPos).
  230.  */
  231. bool
  232. insert_str(TX *tx, const u_char *text, POS *pos)
  233. {
  234.     return(insert_str_n(tx, text, strlen(text), pos));
  235. }
  236.  
  237. bool
  238. insert_str_n(TX *tx, const u_char *text, long textLen, POS *pos)
  239. {
  240.     LINE *line = tx->tx_Lines + pos->pos_Line;
  241.     if(insert_gap(tx, textLen, pos))
  242.     {
  243.     memcpy(line->ln_Line + pos->pos_Col, text, textLen);
  244.     pos->pos_Col += textLen;
  245.     return(TRUE);
  246.     }
  247.     return(FALSE);
  248. }
  249.  
  250. /*
  251.  * Inserts a null teminated string, this routine acts on any '\n' characters
  252.  * that it finds. I expect that this routine will be incredibly slow.
  253.  */
  254. bool
  255. insert_string(TX *tx, const u_char *text, long textLen, POS *pos)
  256. {
  257.     const u_char *eol;
  258.     POS orig = *pos;
  259.     while((eol = memchr(text, '\n', textLen)))
  260.     {
  261.     long len = eol - text;
  262.     if(pos->pos_Col)
  263.     {
  264.         if(len > 0)
  265.         {
  266.         if(!insert_str_n(tx, text, len, pos))
  267.             goto abort;
  268.         }
  269.         if(!split_line(tx, pos))
  270.         goto abort;
  271.         pos->pos_Col = 0;
  272.     }
  273.     else
  274.     {
  275.         u_char *copy;
  276.         if(!resize_line_list(tx, +1, pos->pos_Line))
  277.         goto abort;
  278.         if(!(copy = str_dupn(text, len)))
  279.         goto abort;
  280.         tx->tx_Lines[pos->pos_Line].ln_Strlen = len + 1;
  281.         tx->tx_Lines[pos->pos_Line].ln_Line = copy;
  282.         adjust_marks_add_y(tx, +1, pos->pos_Line);
  283.     }
  284.     textLen -= len + 1;
  285.     text = eol + 1;
  286.     pos->pos_Line++;
  287.     }
  288.     if(textLen > 0)
  289.     {
  290.     if(!insert_str_n(tx, text, textLen, pos))
  291.     {
  292.     abort:
  293.         return(FALSE);
  294.     }
  295.     }
  296.     undo_record_insertion(tx, &orig, pos);
  297.     flag_insertion(tx, &orig, pos);
  298.     return(TRUE);
  299. }
  300.  
  301. /*
  302.  * Deletes some text (this line only)
  303.  */
  304. bool
  305. delete_chars(TX *tx, const POS *pos, long size)
  306. {
  307.     LINE *line = tx->tx_Lines + pos->pos_Line;
  308.     if(line->ln_Strlen)
  309.     {
  310.     u_char *newline;
  311.     if(size >= line->ln_Strlen)
  312.         size = line->ln_Strlen - 1;
  313.     newline = str_alloc(line->ln_Strlen - size);
  314.     if(newline)
  315.     {
  316. #if 1
  317.             memcpy(newline, line->ln_Line, pos->pos_Col);
  318.             memcpy(newline + pos->pos_Col, line->ln_Line + pos->pos_Col + size,
  319.                    line->ln_Strlen - pos->pos_Col - size);
  320. #else
  321.         strncpy(newline, line->ln_Line, pos->pos_Col);
  322.         strcpy(newline + pos->pos_Col, line->ln_Line + pos->pos_Col + size);
  323. #endif
  324.         str_free(line->ln_Line);
  325.         line->ln_Strlen -= size;
  326.         line->ln_Line = newline;
  327.         adjust_marks_sub_x(tx, size, pos->pos_Col, pos->pos_Line);
  328.         return(TRUE);
  329.     }
  330.     mem_error();
  331.     return(FALSE);
  332.     }
  333.     return(TRUE);
  334. }
  335.  
  336. /*
  337.  * deletes some lines
  338.  */
  339. bool
  340. delete_lines(TX *tx, long linenum, long size)
  341. {
  342.     bool rc = FALSE;
  343.     if(resize_line_list(tx, -size, linenum))
  344.     rc = TRUE;
  345.     adjust_marks_sub_y(tx, size, linenum);
  346.     return(rc);
  347. }
  348.  
  349. /*
  350.  * Deletes from startPos to endPos
  351.  */
  352. bool
  353. delete_section(TX *tx, POS *startPos, POS *endPos)
  354. {
  355.     undo_record_deletion(tx, startPos, endPos);
  356.     if(endPos->pos_Line == startPos->pos_Line)
  357.     {
  358.     delete_chars(tx, startPos, endPos->pos_Col - startPos->pos_Col);
  359.     flag_deletion(tx, startPos, endPos);
  360.     }
  361.     else
  362.     {
  363.     long middle;
  364.     bool joinflag = FALSE;
  365.     POS orig = *startPos, oend = *endPos;
  366.     if(startPos->pos_Col)
  367.     {
  368.         long start = tx->tx_Lines[startPos->pos_Line].ln_Strlen - startPos->pos_Col - 1;
  369.         if(start)
  370.         delete_chars(tx, startPos, start);
  371.         startPos->pos_Col = 0;
  372.         startPos->pos_Line++;
  373.         joinflag = TRUE;
  374.     }
  375.     middle = endPos->pos_Line - startPos->pos_Line;
  376.     if(middle != 0)
  377.     {
  378.         delete_lines(tx, startPos->pos_Line, middle);
  379.         endPos->pos_Line -= middle;
  380.     }
  381.     if(endPos->pos_Col)
  382.         delete_chars(tx, startPos, endPos->pos_Col);
  383.     if(joinflag && startPos->pos_Line)
  384.     {
  385.         startPos->pos_Line--;
  386.         startPos->pos_Col = tx->tx_Lines[startPos->pos_Line].ln_Strlen - 1;
  387.         join_lines(tx, startPos);
  388.     }
  389.     flag_deletion(tx, &orig, &oend);
  390.     }
  391.     return(TRUE);
  392. }
  393.  
  394. /*
  395.  * splits the line into two
  396.  */
  397. bool
  398. split_line(TX *tx, POS *pos)
  399. {
  400.     if(resize_line_list(tx, +1, pos->pos_Line + 1))
  401.     {
  402.     LINE *line = tx->tx_Lines + pos->pos_Line;
  403.     u_char *newline1 = str_dupn(line->ln_Line, pos->pos_Col);
  404.     if(newline1)
  405.     {
  406.         long nl2len = line->ln_Strlen - pos->pos_Col;
  407.         u_char *newline2 = str_dupn(line->ln_Line + pos->pos_Col,
  408.                      nl2len - 1);
  409.         if(newline2)
  410.         {
  411.         if(line[0].ln_Line)
  412.             str_free(line[0].ln_Line);
  413.         line[0].ln_Strlen = pos->pos_Col + 1;
  414.         line[0].ln_Line = newline1;
  415.         if(line[1].ln_Line)
  416.             str_free(line[1].ln_Line);
  417.         line[1].ln_Strlen = nl2len;
  418.         line[1].ln_Line = newline2;
  419.         adjust_marks_split_y(tx, pos->pos_Col, pos->pos_Line);
  420.         return(TRUE);
  421.         }
  422.         str_free(newline1);
  423.     }
  424.     }
  425.     mem_error();
  426.     return(FALSE);
  427. }
  428.  
  429. /*
  430.  * joins the current line to the line below it.
  431.  */
  432. static bool
  433. join_lines(TX *tx, POS *pos)
  434. {
  435.     if((pos->pos_Line + 1) < tx->tx_NumLines)
  436.     {
  437.     LINE *line1 = tx->tx_Lines + pos->pos_Line;
  438.     LINE *line2 = line1 + 1;
  439.     int newlen = line1->ln_Strlen + line2->ln_Strlen - 1;
  440.     u_char *newstr = str_alloc(newlen);
  441.     if(newstr)
  442.     {
  443. #if 1
  444.             memcpy(newstr, line1->ln_Line, line1->ln_Strlen - 1);
  445.             memcpy(newstr + (line1->ln_Strlen - 1), line2->ln_Line, line2->ln_Strlen);
  446. #else
  447.         stpcpy(stpcpy(newstr, line1->ln_Line), line2->ln_Line);
  448. #endif
  449.         resize_line_list(tx, -1, pos->pos_Line);
  450.         line1 = tx->tx_Lines + pos->pos_Line;
  451.         if(line1->ln_Line)
  452.         str_free(line1->ln_Line);
  453.         line1->ln_Strlen = newlen;
  454.         line1->ln_Line = newstr;
  455.         adjust_marks_join_y(tx, pos->pos_Col, pos->pos_Line);
  456.         return(TRUE);
  457.     }
  458.     mem_error();
  459.     }
  460.     return(FALSE);
  461. }
  462.  
  463. /*
  464.  * Inserts spaces from end of line to pos
  465.  */
  466. bool
  467. pad_pos(TX *tx, POS *pos)
  468. {
  469.     if(pos->pos_Line < tx->tx_NumLines)
  470.     {
  471.     LINE *line = tx->tx_Lines + pos->pos_Line;
  472.     if(line->ln_Strlen < (pos->pos_Col + 1))
  473.     {
  474.         u_char *newline = str_alloc(pos->pos_Col + 1);
  475.         if(newline)
  476.         {
  477.         long i;
  478.         POS start;
  479.         start.pos_Line = pos->pos_Line;
  480.         start.pos_Col = line->ln_Strlen - 1;
  481.         undo_record_insertion(tx, &start, pos);
  482.         /* No need to call flag_insertion() since there's nothing
  483.            that needs redrawing. */
  484.                 memcpy(newline, line->ln_Line, line->ln_Strlen - 1);
  485.         for(i = line->ln_Strlen - 1; i < pos->pos_Col; i++)
  486.             newline[i] = ' ';
  487.         newline[i] = 0;
  488.         if(line->ln_Line)
  489.             str_free(line->ln_Line);
  490.         line->ln_Strlen = pos->pos_Col + 1;
  491.         line->ln_Line = newline;
  492.         return(TRUE);
  493.         }
  494.         mem_error();
  495.         pos->pos_Col = line->ln_Strlen - 1;
  496.         return(FALSE);
  497.     }
  498.     return(TRUE);
  499.     }
  500.     return(FALSE);
  501. }
  502.  
  503. bool
  504. pad_cursor(VW *vw)
  505. {
  506.     return(pad_pos(vw->vw_Tx, &vw->vw_CursorPos));
  507. }
  508.  
  509. /*
  510.  * if end is before start then swap the two
  511.  */
  512. void
  513. order_pos(POS *start, POS *end)
  514. {
  515.     if(((start->pos_Line == end->pos_Line) && (start->pos_Col > end->pos_Col))
  516.      || (start->pos_Line > end->pos_Line))
  517.     {
  518.     POS temp;
  519.     temp = *start;
  520.     *start = *end;
  521.     *end = temp;
  522.     }
  523. }
  524.  
  525. bool
  526. check_section(TX *tx, POS *start, POS *end)
  527. {
  528.     order_pos(start, end);
  529.     if((start->pos_Line >= tx->tx_NumLines)
  530.        || (end->pos_Line >= tx->tx_NumLines)
  531.        || (start->pos_Line < 0)
  532.        || (end->pos_Line < 0))
  533.     return(FALSE);
  534.     if(start->pos_Col >= tx->tx_Lines[start->pos_Line].ln_Strlen)
  535.     start->pos_Col = tx->tx_Lines[start->pos_Line].ln_Strlen - 1;
  536.     if(end->pos_Col >= tx->tx_Lines[end->pos_Line].ln_Strlen)
  537.     end->pos_Col = tx->tx_Lines[end->pos_Line].ln_Strlen - 1;
  538.     return(TRUE);
  539. }
  540.  
  541. void
  542. check_pos(TX *tx, POS *pos)
  543. {
  544.     if(pos->pos_Line >= tx->tx_NumLines)
  545.     pos->pos_Line = tx->tx_NumLines - 1;
  546.     else if(pos->pos_Line < 0)
  547.     pos->pos_Line = 0;
  548.     if(pos->pos_Col >= tx->tx_Lines[pos->pos_Line].ln_Strlen)
  549.     pos->pos_Col = tx->tx_Lines[pos->pos_Line].ln_Strlen - 1;
  550. }
  551.  
  552. bool
  553. check_line(TX *tx, POS *pos)
  554. {
  555.     if((pos->pos_Line >= tx->tx_NumLines) || (pos->pos_Line < 0)
  556.        || (pos->pos_Col < 0))
  557.     return(FALSE);
  558.     return(TRUE);
  559. }
  560.  
  561. /*
  562.  * Returns the number of bytes needed to store a section, doesn't include
  563.  * a zero terminator but does include all newline chars.
  564.  */
  565. long
  566. section_length(TX *tx, POS *startPos, POS *endPos)
  567. {
  568.     long linenum = startPos->pos_Line;
  569.     LINE *line = tx->tx_Lines + linenum;
  570.     long length;
  571.     if(startPos->pos_Line == endPos->pos_Line)
  572.     length = endPos->pos_Col - startPos->pos_Col;
  573.     else
  574.     {
  575.     length = line->ln_Strlen - startPos->pos_Col;
  576.     linenum++;
  577.     line++;
  578.     while(linenum < endPos->pos_Line)
  579.     {
  580.         length += line->ln_Strlen;
  581.         linenum++;
  582.         line++;
  583.     }
  584.     length += endPos->pos_Col;
  585.     }
  586.     return(length);
  587. }
  588.  
  589. /*
  590.  * Copies a section to a buffer.
  591.  * end of copy does NOT have a zero appended to it.
  592.  */
  593. void
  594. copy_section(TX *tx, POS *startPos, POS *endPos, u_char *buff)
  595. {
  596.     long linenum = startPos->pos_Line;
  597.     LINE *line = tx->tx_Lines + linenum;
  598.     long copylen;
  599.     if(startPos->pos_Line == endPos->pos_Line)
  600.     {
  601.     copylen = endPos->pos_Col - startPos->pos_Col;
  602.     memcpy(buff, line->ln_Line + startPos->pos_Col, copylen);
  603.     buff[copylen] = 0;
  604.     }
  605.     else
  606.     {
  607.     copylen = line->ln_Strlen - startPos->pos_Col - 1;
  608.     memcpy(buff, line->ln_Line + startPos->pos_Col, copylen);
  609.     buff[copylen] = '\n';
  610.     buff += copylen + 1;
  611.     linenum++;
  612.     line++;
  613.     while(linenum < endPos->pos_Line)
  614.     {
  615.         copylen = line->ln_Strlen - 1;
  616.         memcpy(buff, line->ln_Line, copylen);
  617.         buff[copylen] = '\n';
  618.         buff += copylen + 1;
  619.         linenum++;
  620.         line++;
  621.     }
  622.     memcpy(buff, line->ln_Line, endPos->pos_Col);
  623.     }
  624. }
  625.  
  626. /*
  627.  * returns TRUE if the specified position is inside a block
  628.  */
  629. bool
  630. pos_in_block(VW *vw, long col, long line)
  631. {
  632.     if((vw->vw_BlockStatus)
  633.        || (line < vw->vw_BlockS.pos_Line)
  634.        || (line > vw->vw_BlockE.pos_Line))
  635.     return(FALSE);
  636.     if(vw->vw_Flags & VWFF_RECTBLOCKS)
  637.     {
  638.     long start_col = glyph_col(vw->vw_Tx, vw->vw_BlockS.pos_Col,
  639.                    vw->vw_BlockS.pos_Line);
  640.  
  641.     long end_col = glyph_col(vw->vw_Tx, vw->vw_BlockE.pos_Col,
  642.                  vw->vw_BlockE.pos_Line);
  643.     col = glyph_col(vw->vw_Tx, col, line);
  644.     if(start_col < end_col)
  645.     {
  646.         if((col < start_col) || (col >= end_col))
  647.         return(FALSE);
  648.     }
  649.     else
  650.     {
  651.         if((col < end_col) || (col >= start_col))
  652.         return(FALSE);
  653.     }
  654.     }
  655.     else
  656.     {
  657.     if(((line == vw->vw_BlockS.pos_Line) && (col < vw->vw_BlockS.pos_Col))
  658.       || ((line == vw->vw_BlockE.pos_Line) && (col >= vw->vw_BlockE.pos_Col)))
  659.     return(FALSE);
  660.     }
  661.     return(TRUE);
  662. }
  663.  
  664. bool
  665. cursor_in_block(VW *vw)
  666. {
  667.     return(pos_in_block(vw, vw->vw_CursorPos.pos_Col, vw->vw_CursorPos.pos_Line));
  668. }
  669.  
  670.  
  671. bool
  672. page_in_block(VW *vw)
  673. {
  674.     if((vw->vw_BlockStatus)
  675.       || ((vw->vw_BlockE.pos_Line + 1) < vw->vw_StartLine)
  676.       || (vw->vw_BlockS.pos_Line > vw->vw_StartLine + vw->vw_MaxY))
  677.     return(FALSE);
  678.     return(TRUE);
  679. }
  680.  
  681. /*
  682.  * these returns,
  683.  *
  684.  *    0   line not in block
  685.  *    1   whole line in block
  686.  *    2   start of line in block
  687.  *    3   end of line in block
  688.  *    4   middle of line in block
  689.  *
  690.  * note:
  691.  *  this isn't very intelligent (but it works :-).
  692.  *
  693.  * now handles rectangular blocks (VWFF_RECTBLOCKS)
  694.  */
  695. short
  696. line_in_block(VW *vw, long line)
  697. {
  698.     bool startin = FALSE;
  699.     bool endin = FALSE;
  700.  
  701.     if((vw->vw_BlockStatus)
  702.       || (line < vw->vw_BlockS.pos_Line)
  703.       || (line > vw->vw_BlockE.pos_Line))
  704.     return(0);
  705.     if(vw->vw_Flags & VWFF_RECTBLOCKS)
  706.     return(4);
  707.     if(line == vw->vw_BlockE.pos_Line)
  708.     startin = TRUE;
  709.     if(line == vw->vw_BlockS.pos_Line)
  710.     endin = TRUE;
  711.     if(startin)
  712.     {
  713.     if(endin)
  714.         return(4);
  715.     return(2);
  716.     }
  717.     if(endin)
  718.     return(3);
  719.     return(1);
  720. }
  721.  
  722. /*
  723.  * makes sure that the marked block is valid
  724.  */
  725. void
  726. order_block(VW *vw)
  727. {
  728.     if(!vw->vw_BlockStatus)
  729.     {
  730.     if(vw->vw_BlockS.pos_Line > vw->vw_BlockE.pos_Line)
  731.     {
  732.         POS temp = vw->vw_BlockE;
  733.         vw->vw_BlockE = vw->vw_BlockS;
  734.         vw->vw_BlockS = temp;
  735.     }
  736.     else if(vw->vw_BlockS.pos_Line == vw->vw_BlockE.pos_Line)
  737.     {
  738.         if(vw->vw_BlockS.pos_Col > vw->vw_BlockE.pos_Col)
  739.         {
  740.         POS temp = vw->vw_BlockE;
  741.         vw->vw_BlockE = vw->vw_BlockS;
  742.         vw->vw_BlockS = temp;
  743.         }
  744.     }
  745.     }
  746. }
  747.  
  748. /*
  749.  * Set up the refresh flags to refresh the block in the most efficient manner.
  750.  */
  751. void
  752. set_block_refresh(VW *vw)
  753. {
  754.     long endline = vw->vw_StartLine + vw->vw_MaxY;
  755.     if((vw->vw_BlockS.pos_Line > endline)
  756.        || (vw->vw_BlockE.pos_Line < vw->vw_StartLine))
  757.     return;
  758.     if(vw->vw_Flags & VWFF_REFRESH_BLOCK)
  759.     /*
  760.      * If the all-powerful bit is already set I have no way of telling
  761.      * myself to refresh two blocked areas, stupid huh? Anyway I just
  762.      * blast in the whole window instead.
  763.      */
  764.     vw->vw_Flags |= VWFF_FORCE_REFRESH;
  765.     else
  766.     vw->vw_Flags |= VWFF_REFRESH_BLOCK;
  767. }
  768.  
  769. bool
  770. read_only(TX *tx)
  771. {
  772.     if(tx->tx_Flags & TXFF_RDONLY)
  773.     {
  774.     VALUE tmp = cmd_symbol_value(sym_inhibit_read_only, sym_t);
  775.     if(VOIDP(tmp) || NILP(tmp))
  776.     {
  777.         cmd_signal(sym_buffer_read_only, LIST_1(VAL(tx)));
  778.         return(TRUE);
  779.     }
  780.     }
  781.     return(FALSE);
  782. }
  783.